<?php
namespace Communal\Controller;
use Common\Controller\CommonController;

/**
 * 定时任务(cronjob)模块
 */
class CronController extends CommonController {
	
	protected $push_data = '';
	protected $words_num = 60;
	protected $push_msg;
	protected $push_url;
	protected $message_content;
	protected $talkRedisIdx = 0;
	protected $hasMsg;
	protected $msgType;
	
	
	protected function _initialize(){
		parent::_initialize();
		$this->_mycache = S(C('REDIS_DSN'));
		
		$this->msgType = array(
				1 => L('MSG_TYPE_1'),
				2 => L('MSG_TYPE_2'),
				3 => L('MSG_TYPE_3'),
				4 => L('MSG_TYPE_4'),
				5 => L('MSG_TYPE_5'),
				6 => L('MSG_TYPE_6'),
				7 => L('MSG_TYPE_7'),
				8 => L('MSG_TYPE_8'),
				9 => L('MSG_TYPE_9'),
				10 => L('MSG_TYPE_10'),
				11 => L('MSG_TYPE_11'),
				12 => L('MSG_TYPE_12'),
				13 => L('MSG_TYPE_13'),
				14 => L('MSG_TYPE_14'),
				15 => L('MSG_TYPE_15'),
				16 => L('MSG_TYPE_16'),
				17 => L('MSG_TYPE_17'),
				18 => L('MSG_TYPE_18'),
				19 => L('MSG_TYPE_19'),
				20 => L('MSG_TYPE_20'),
				21 => L('MSG_TYPE_21'),
				22 => L('MSG_TYPE_22'),
				23 => L('MSG_TYPE_23'),
				24 => L('MSG_TYPE_24'),
				25 => L('MSG_TYPE_25'),
				26 => L('MSG_TYPE_26'),
				27 => L('MSG_TYPE_27'),
				28 => L('MSG_TYPE_28'),
				29 => L('MSG_TYPE_29'),
				30 => L('MSG_TYPE_30'),
				31 => L('MSG_TYPE_31'),
				32 => L('MSG_TYPE_32'),
				33 => L('MSG_TYPE_33'),
				34 => L('MSG_TYPE_34'),
				35 => L('MSG_TYPE_35'),
				36 => L('MSG_TYPE_36'),
				37 => L('MSG_TYPE_37'),
				39 => L('MSG_TYPE_39'),
				40 => L('MSG_TYPE_40'),
				41 => L('MSG_TYPE_41'),
				45 => L('MSG_TYPE_45'),
				46 => L('MSG_TYPE_46'),
		);
	}
	
	
	
    /**
     * IOS推送
     */
    public function iosPushAction(){
    	//  /alidata/server/php/bin/php index.php Communal/Cron/iosPush/[参数名/参数值...]
    	set_time_limit(0);
    	ini_set('memory_limit','2048M');
    	
    	if(__ENV__ == "production"){
    		$pem_file = './ck/ck.pem';
    		$pem_password = '123456';
    		$this->push_url = 'ssl://gateway.push.apple.com:2195';
    		$feedback_url = 'ssl://feedback.push.apple.com:2196';
    	}else{
    		$pem_file = './ck/ck_dev.pem';
    		$pem_password = '123456';
    		$this->push_url = 'ssl://gateway.sandbox.push.apple.com:2195';
    		$feedback_url = 'ssl://feedback.sandbox.push.apple.com:2196';
    	}
    		
    	$ctx = stream_context_create();
    	stream_context_set_option($ctx, 'ssl', 'local_cert', $pem_file);
    	stream_context_set_option($ctx, 'ssl', 'passphrase', $pem_password);
    	
    	$startTime = time();
    	while(true){
    		if(time() - $startTime > 86400) break;
    		
    		try {
    			$ret = $this->_pushMsg($ctx);
    			if($ret === false) sleep(5);
    		} catch (\Exception $e) {
    			$this->_logError($e->getMessage() , "push_error");
    			sleep(3);
    		}
    	}
    }
    
    private function _pushMsg($ctx){
    	$fp = stream_socket_client($this->push_url, $errno, $errstr, 50, STREAM_CLIENT_CONNECT, $ctx);
    	if($fp === false){
    		$this->_logError("can't connect: ios-APNS " . $errno . $errstr , "push_error");
    		@fclose($fp);
    		return false;
    	}
    	
    	$redisArr = C('CHAT_REDIS_DSN');
    	while(true){
    		if(empty($this->push_data)){
    			$create_return = $this->_createPayload();
    			$msg_create_result = $this->_getEchoMsgByReturn($create_return);
    			
    			if ($create_return === 0) {
    				$this->push_data = '';
    				
    				$num = 0;
    				foreach($redisArr as $idx=>$redis){
    					if($this->hasMsg[$idx] === 0){
    						$num++;
    					}
    				}
    				
    				if($num == count($redisArr)){
    					break;//全部redis实例中都没有未读消息时就跳出
    				}else{
    					continue;
    				}
    			}
    			
    			
    			if ($msg_create_result !== true) {
    				$this->_logError("[" . $this->push_msg . "]" . $this->message_content . "\t" . $msg_create_result , "push_error");
    				$this->push_data = '';
    				continue;
    			}
    			$this->_logError("[" . $this->push_msg . "]" . $this->message_content . "\t" , "push_error");
    		}
    	
    		$push_data = $this->push_data;
    		$push_body = $push_data['push_payload'];
    		$push_body_json = json_encode($push_body);
    		$device_no = $push_data['device_no'];
    	
    		$this->_logError("device_no : " . $device_no  . "\t" , "push_error");
    	
    		$msg = chr(0) . pack("n", 32) . pack('H*', str_replace(' ', '', $device_no)) . pack("n", strlen($push_body_json)) . $push_body_json;
    	
    		/*ssl链接因为某些原因断开，该推送消息从新回到等待推送队列里面，并记录错误日志。*/
    		$ret = false;
    		$loop = 0;
    		while($ret===false && $loop < 3){
    			$ret = fwrite($fp, $msg);
    			$loop++;
    		}
    			
    		if ($ret===false) {
    			$this->_logError("push failure" , "push_error");
    			$this->push_data = '';
    			break;
    		}
    		$this->_logError("push success" , "push_error");
    		$this->push_data = '';
    	}
    	@fclose($fp);
    	sleep(5);
    	
    }
    
    
	//组装数据
	private function _createPayload() {
		$this->push_data = '';
		$body = array();
		$redisArr = C('CHAT_REDIS_DSN');
		
		foreach($redisArr as $redisIdx=>$redisDSN){
			if(empty($this->_talkcache[$redisIdx])) $this->_talkcache[$redisIdx] = S($redisDSN);
			
			if(empty($this->_talkcache[$redisIdx])){
				$this->push_data = '';
				$this->push_msg = '';
				$this->_logError("can't connect redis server[{$redisIdx}]" , "push_error");
				//TODO邮件或及时消息通知运维人员
				exit;
			}
		}
		
		$currIdx = $this->talkRedisIdx;
		$this->push_msg = $the_unread_msg = $this->_talkcache[$this->talkRedisIdx]->lpop(\cachekey::$key['TALK_KEY_CONF']['PUSH_LIST']);
		$this->talkRedisIdx++;
		if($this->talkRedisIdx >= count($redisArr)) $this->talkRedisIdx = 0;
		if(!empty($the_unread_msg)){
			$this->hasMsg[$currIdx] = 1;
		}else{
			$this->hasMsg[$currIdx] = 0;
			return 0;
		}
		

		$the_msg_info = explode(":", $the_unread_msg);
		if (empty($the_msg_info[1])) {
			return 1;
		}
		$push_cust = $the_msg_info[0];
		$msg_id = $the_msg_info[1];


		//取出推送人的推送记录
		$device_no = $this->_mycache->hget(\cachekey::$key['TALK_KEY_CONF']['CUST_DEVICE'], $push_cust);
		if (empty($device_no)) {
			return 2;
		}
		
		$cust_id = $this->_mycache->hget(\cachekey::$key['TALK_KEY_CONF']['DEVICE_CUST'], $device_no);
		if($cust_id != $push_cust){
			return 8;
		}
		
		//根据hash值决定从哪个实例取消息
		if($msg_id[0] == "-"){
			$tmp_msg_id = bcadd("18446744073709551616" , $msg_id);
		}else{
			$tmp_msg_id = $msg_id;
		}
		$msgRedisIdx = \tools::talkCacheHash($tmp_msg_id , count($redisArr));
		if(empty($this->_talkcache[$msgRedisIdx])){
			$this->_talkcache[$msgRedisIdx] = S($redisArr[$msgRedisIdx]);
		}
		
		$message_array = $this->_talkcache[$msgRedisIdx]->get($msg_id);
		$this->message_content = json_encode($message_array);
		if (empty($message_array)) {
			return 3;
		}

		//判断是否是本人所发信息
		if ($message_array['from_cust_id'] == $push_cust) {
			return 4;
		}

		$chatid = $message_array['chat_id'];
		$tcustid = $push_cust;
		$fcustid = $message_array['from_cust_id'];
		
		if($chatid != 0) {
			//判断tcustid是否还存在聊天群
			$custList = $this->_getChatCust($chatid);
			if(empty($custList)){
				return 9;
			}
			
			$key = \cachekey::$key['BASE_KEY_CONF']['NO_PUSH_CHAT'] . $chatid;
			$ret = $this->_mycache->sismember($key , $tcustid);
			if($ret){
				return 6;
			}
		}else{
			$key = \cachekey::$key['BASE_KEY_CONF']['NO_PUSH_CUST'] . $fcustid;
			$ret = $this->_mycache->sismember($key , $tcustid);
			if($ret){// && $fcustid!=10000
				return 6;
			}
		}
		
		$key = \cachekey::$key['BASE_KEY_CONF']['NO_PUSH_CUSTS'];
		$ret = $this->_mycache->sismember($key , $tcustid);
		if($ret){
			return 6;
		}

		//声音处理
		$sound = 1;//全部有音
		$at = $message_array['content']['at'];
		if (!in_array($at, $push_cust)) {
			
			if ($this->_mycache->sismember(\cachekey::$key['BASE_KEY_CONF']['NO_SOUND_CUSTS'], $tcustid) && $fcustid!=10000) {
				$sound = 0;
			}
		}

		$content = $message_array['content']['content'];
		$content_param = $message_array['content']['content_param'];
		if(!empty($content_param)){
			foreach($content_param as $idx=>$param){
				if(!empty($param)) $content = str_replace("{.$idx.}",$param['nickname'],$content);
			}
		}
		
		$from_cust_name = $message_array['content']['from_cust_name'];
		if(empty($from_cust_name)) {
			$custInfo = $this->_getCustInfo($fcustid);
			$from_cust_name = $custInfo['nickname'];//$this->_mycache->hGET('cust:name', $fcustid);
		}
		
		//文本直接截取 words_num个字，视频，图片等 直接显示MSG_TYPE
		$msg_type = $message_array['content']['type'];
		$nonpush_type = array(14,26,35,36,37,39,40,41,45,46);
		if(in_array($msg_type , $nonpush_type)) {
			return 7;
		}
		$chat_type = $message_array['chat_type'];
		if ($chat_type == 0) {
			$from_cust_name = $message_array['content']['from_cust_name'];
			if(!empty($from_cust_name))$from_cust_name = $from_cust_name . ":";
			$body['aps']['alert'] = $from_cust_name . \tools::truncate($content, $this->words_num);
		} else {
			if(!empty($from_cust_name))$from_cust_name = $from_cust_name . ":";
			if ($msg_type == 1) {
				$body['aps']['alert'] = $from_cust_name . \tools::truncate($content, $this->words_num);
			} else {
				$body['aps']['alert'] = $from_cust_name . "[" . $this->msgType[$msg_type] . "]";
			}
		}

		//图标显示数目
		$body['aps']['badge'] = $this->_mycache->hIncrBy(\cachekey::$key['TALK_KEY_CONF']['PUSH_NOTICE_COUNT'], $push_cust, 1);
		
		if ($sound == 1) {
			$body['aps']['sound'] = 'default';
		}
		
		
		if(!empty($message_array['content']['ext_content'])){
			$body['ext_content'] = $message_array['content']['ext_content'];
		}
		
		
		$this->push_data = array('push_payload' => $body, 'device_no' => $device_no); 
		return 5;
	}

	private function _getEchoMsgByReturn($create_return) {
		$return = false;
		switch ($create_return) {
			case 1:
				$return =  1 ;
				break;
			case 2:
				$return =  'user is not ios'; //要推送的用户不是苹果用户
				break;
			case 3:
				$return =  'in redis , message is not exist'; //给出的msg_id在redis中找不到
				break;
			case 4:
				$return =  'message is sended by self'; //要推送的信息是用户自己发送的
				break;
			case 5:
				$return = true;
				break;
			case 6:
				$return =  'forbid push message';//设置了禁止推送
				break;
			case 7:
				$return =  'no push for this message type';//这种消息类型不用推送
				break;
			case 8:
				$return =  'device is un-ios';//该设备已被其他帐号使用
				break;
			case 9:
				$return =  'user is not in the group';//该帐号不在群里了
				break;
			default:
				$return =  'unknown';//返回未知代码
				break;
		}
		return $return;
	}
	
	
	
	public function getAllMsgAction(){
		//  /alidata/server/php/bin/php index.php Communal/Cron/getAllMsg/[参数名/参数值...]
		$startTime = time();
		while(true){
			if(time() - $startTime > 86400) break;
			
			$allMsg = new \Common\Model\AllMsgModel();
			$redisArr = C('CHAT_REDIS_DSN');
			
			foreach($redisArr as $msgRedisIdx=>$redisDSN){
				if(empty($this->_talkcache[$msgRedisIdx])){
					$this->_talkcache[$msgRedisIdx] = S($redisArr[$msgRedisIdx]);
				}
				
				$msg = true;
				while($msg){
					$msg = $this->_talkcache[$msgRedisIdx]->lpop(\cachekey::$key['TALK_KEY_CONF']['MSG_ALL']);
					if(empty($msg)) break;
					$msgArr = json_decode($msg , true);
					if(!empty($msgArr)){
						$data = array();
						$data['chatid'] = $msgArr['chat_id'];
						$data['chattype'] = $msgArr['chat_type'];
						$data['fromcustid'] = $msgArr['from_cust_id'];
						$data['tocustid'] = $msgArr['to_cust_id'];
						$data['msgid'] = $msgArr['msg_id'];
						$data['msgno'] = $msgArr['msg_no'];
						$data['msgtype'] = $msgArr['msg_type'];
						$data['msgtime'] = $msgArr['msg_time'];
						$data['logintype'] = $msgArr['login_type'];
						$data['msgexpiretime'] = $msgArr['msg_expire_time'];
						
						if(!empty($msgArr['content']['content_param'])){
							foreach($msgArr['content']['content_param'] as $idx=>$param){
								if(!empty($param)) $msgArr['content']['content'] = str_replace("{.$idx.}",$param['nickname'],$msgArr['content']['content']);
							}
						}
						
						$data['content'] = json_encode($msgArr['content']);
						
						if(!empty($msgArr['content']['from_cust_id']) && empty($msgArr['from_cust_id'])) $data['fromcustid'] = $msgArr['content']['from_cust_id'];
						if(!empty($msgArr['content']['to_cust_id']) && empty($msgArr['to_cust_id'])) $data['tocustid'] = $msgArr['content']['to_cust_id'];
						
						try{
							$allMsg->addMsg($data);
							
							$custInfo = $this->_getCustInfo($data['tocustid']);
							$fcustname = $custInfo['nickname'];
							$publicnoid = $custInfo['publicnoid'];
							$keywords = $msgArr['content']['content'];
							if($publicnoid) $this->autoReply($fcustname , $data['tocustid'] , $keywords , $data['fromcustid'] , $publicnoid);
							
						}catch (\Exception $e) {
							$this->_logError($e->getMessage() , "save_msg_error");
						}
					}
				}
			}
			
			sleep(3);
		}
		
	}
	
	
	private function autoReply($fcustname , $fromcustid , $keywords , $tocustid , $publicnoid){
		$key = \cachekey::$key['AUTO_REPLY_KEYWORD'] . $publicnoid . ":" . md5($keywords);
		$replycontent = $this->_mycache->get($key);
		if(!empty($replycontent)){
			$msg['from_cust_name'] = $fcustname;
			$msg['from_cust_id'] = (int)$fromcustid;
			$msg['to_cust_id'] = (int)$tocustid;
			$msg['type'] = 1;
			$msg['session_type'] = 1;
			$msg['session_id'] = (int)$fromcustid;
			$msg['content'] = $replycontent;
			$msg['custtype'] = "3";
			$msg['operationType'] = 4;//公众号
			\im::sendMsg(3, array($tocustid), array(), $msg);
		}
	}
	
	
}
